package com.credithc.eagleeye.api.utils;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.credithc.eagleeye.api.exception.AuthTokenException;
import com.credithc.eagleeye.api.vo.AuthTokenVo;
import com.credithc.framework.utils.json.FastJsonConvert;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
/**
 * 描 述: <br/>
 * 作 者: zhangjin<br/>
 * 创 建：2018年02月06日<br/>
 * 版 本：v1.0.0<br>
 * <p>
 * 历 史: (版本) 作者 时间 注释 <br/>
 */
@Slf4j
public class JWTUtils {
    private String JWT_HEADER = "";
    private Algorithm algorithm;
    private long expireTimeMillis=24*60*60*1000;
    private AtomicBoolean initState = new AtomicBoolean(false);

    private static AESUtils aesUtils=null;

    private static class SingletonHolder {
        static final JWTUtils instance = new JWTUtils();
    }

    public static JWTUtils getInstance() {
        return JWTUtils.SingletonHolder.instance;
    }
    public void init(String jwtSecretKey,long jwtExpireTimeSeconds,String aesSecretKeySeed,String aesIvParameterSeed) throws UnsupportedEncodingException {
        if (initState.compareAndSet(false, true)) {
            this.algorithm = Algorithm.HMAC256(jwtSecretKey);
            if(jwtExpireTimeSeconds>0) {
                this.expireTimeMillis = jwtExpireTimeSeconds * 1000;
            }
            this.JWT_HEADER = StringUtils.substringBefore(JWT.create().sign(Algorithm.HMAC256(jwtSecretKey)), ".")+".";
            aesUtils = new AESUtils(aesSecretKeySeed, aesIvParameterSeed);
        }else{
            log.error("重复初始化JWT");
        }
    }

    /**
     * 获取java web token
     */
    public String encodeJWT(AuthTokenVo authTokenVo) {
        return encodeJWT(authTokenVo,this.expireTimeMillis);
    }

    /**
     * 获取java web token
     */
    public String encodeJWT(AuthTokenVo authTokenVo,long expireTimeMillis){
        String token = JWT.create()
                .withExpiresAt(new Date(System.currentTimeMillis()+expireTimeMillis))
                .withClaim("userName",authTokenVo.getUserName())
                .withClaim("sessionId",authTokenVo.getSessionId())
                .sign(algorithm);
        try {
            token = aesUtils.aesEncrypt(StringUtils.removeStart(token, JWT_HEADER));
        } catch (Exception ex) {
            ex.printStackTrace();
            token = "";
        }
        return token;
    }

    public AuthTokenVo decodeJWT(String token) {
        AuthTokenVo authTokenVo =new AuthTokenVo();
        try {
            if (StringUtils.isBlank(token)) {
                throw new AuthTokenException("无效token");
            }
            String decryptJwtToken = aesUtils.aesDecrypt(token);
            JWTVerifier verifier = JWT.require(algorithm).build();
            DecodedJWT jwt = verifier.verify(StringUtils.join(JWT_HEADER,decryptJwtToken));
            long expiresAt = jwt.getExpiresAt()==null?0:jwt.getExpiresAt().getTime();
            if(System.currentTimeMillis()>expiresAt){
                throw new AuthTokenException("token有效期超期");
            }
            Map<String, Claim> claims = jwt.getClaims();
            authTokenVo.setUserName(claims.get("userName")==null?"":claims.get("userName").asString());
            authTokenVo.setSessionId(claims.get("sessionId")==null?"":claims.get("sessionId").asString());
            authTokenVo.setExpiresAt(expiresAt);

        } catch (Exception exception){
            throw new AuthTokenException("无效token");
        }
        return authTokenVo;
    }
    public static void main(String[] args) throws UnsupportedEncodingException {
        String jwtSecretKey = "%^*23bcj*^^TG7";
        String secretKeySeed = "!$@C438ai%^2^&*b";
        String ivParameterSeed = "dlr-api-iv-param";
        JWTUtils.getInstance().init(jwtSecretKey,60*60*1000,secretKeySeed,ivParameterSeed);

        AuthTokenVo authTokenVo = new AuthTokenVo();
        authTokenVo.setSessionId(UUID.randomUUID().toString().replaceAll("-",""));
        String token = JWTUtils.getInstance().encodeJWT(authTokenVo);
        System.out.println(token);
        AuthTokenVo authTokenVo1 = JWTUtils.getInstance().decodeJWT(token);
        System.out.println(FastJsonConvert.convertObjectToJSON(authTokenVo1));


    }
}
